home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / MacGofer 0.22d / MacGofer Sources / mac_main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-08  |  24.7 KB  |  1,013 lines  |  [TEXT/MPS ]

  1. /*****************************************************************************
  2.  
  3.   main.c:  Copyright (c) Kevin Hammond 1993.   All rights reserved.
  4.   
  5.   This is the main module for the Gofer Mac interface. 
  6.   
  7.   The routines in this module handle initialisation, the main event loop
  8.   and top-level event dispatching.
  9.  
  10. *****************************************************************************/
  11.  
  12. #pragma segment GMain
  13.  
  14. #include "mac.h"
  15. #include <AppleEvents.h>
  16. #include <Errors.h>
  17.  
  18. CursHandle ibeamcurs, watchcurs;                /* Ibeam and Watch cursors             */
  19. CursHandle gccurs;                              /* Cursor used during GC             */
  20. CCrsrHandle gccursc;                /* Colour version of above             */
  21.  
  22. EventRecord myEvent;                /* Main event record                 */
  23. Boolean WNEAvailable      = FALSE;        /* WaitNextEvent available             */
  24. Boolean CCAvailable       = FALSE;        /* Colour Cursors available             */
  25. Boolean CIAvailable       = FALSE;        /* Colour Icons available             */
  26. Boolean HasAppleEvents    = FALSE;        /* Supports System-7 AppleEvents         */
  27. Boolean inForeground      = TRUE;        /* Are we in the background?             */
  28. Boolean MemoryInstalledOK = FALSE;        /* True once the memory's been initialised     */
  29. Boolean GoferInitialised  = FALSE;        /* True once the interface is initialised     */
  30. Boolean InterpreterInitialised  = FALSE;    /* True once Gofer's completely initialised     */
  31.  
  32. short  systemVersion = 0x0000;            /* System software version             */
  33. short  goferWDRefNum = 0;            /* Gofer's working directory's refnum         */
  34. short  gofervol = 0;                /* Gofer's "real" vRefNum             */
  35. long   goferdirID = 0;                /* Gofer's "real" dirID             */
  36. short  goferresfile = -1;            /* Gofer's resource file no.             */    
  37.  
  38. static RgnHandle cursorRgn;            /* Cursor region for WaitNextEvent         */
  39.  
  40. Boolean quit = FALSE;                /* Set when finished                 */
  41.  
  42. extern jmp_buf catch_error;            /* The error jump buffer, used by longjmp    */
  43.  
  44. Bool    USER_ABORT = FALSE;            /* Has the user Pressed CMD-.             */
  45. extern  Boolean EOFread;            /* Has the user Pressed CMD-ENTER         */
  46. extern  Boolean HandlingEvents;            /* Is the Programmer Handling Events in Gofer      */
  47.  
  48. int HeapPC =          DEFAULT_HEAP_PERCENTAGE;    /* % Remaining memory for Heap             */
  49. unsigned MinMemSize = DEFAULT_MIN_MEM_SIZE;    /* Minimum Memory to run in             */
  50. #define  MIN_INIT_SIZE    320000            /* Minimum Memory to start up             */
  51.  
  52. unsigned ExtraStack = 0;                /* How much extra stack to reserve on startup   */
  53.  
  54.  
  55. char *undoBuffer=NIL;                /* The characters which can be "undone"        */
  56.  
  57.  
  58. /* Forward declarations */
  59.  
  60. Boolean cursorkey();                /* Is this key a cursor key            */
  61. extern OSType preftype;                /* The type of the Gofer Preferences file    */
  62. extern Boolean scrapVisible;            /* Is the scrap (clipboard) window visible    */
  63. extern DescType savemethod;                     /* How to do global saves                       */
  64.  
  65.  
  66. /*****************************************************************************
  67.  
  68.     Interacting with our environment.
  69.  
  70. ******************************************************************************/
  71.  
  72.  
  73. /* 
  74.   ObtainEnvironment determines whether WaitNextEvent etc are available.
  75.   System 7 should use Gestalt -- KH 
  76. */
  77.  
  78. #define  WNETrapNumber  0xA860                     /* WaitNextEvent trap             */
  79. #define  CCTrapNumber   0xAA1B                     /* GetCCursor trap                 */
  80. #define  CITrapNumber   0xAA1E                     /* GetCIcon trap                */
  81.  
  82. extern savedir(short vrefnum, long dirID, Boolean reset);
  83.  
  84. ObtainEnvironment()
  85. {
  86.   SysEnvRec environ;
  87.   Str255 goferVolName;
  88.  
  89.   /* If no default volume, use Gofer's folder  */
  90. //  if(GetVol(goferVolName, &goferWDRefNum) != noErr)
  91.   if(TRUE)
  92.     {
  93.        FCBPBRec fcb;
  94.        fcb.ioNamePtr = NULL;
  95.        fcb.ioCompletion = NULL;
  96.        fcb.ioVRefNum = 0;
  97.        fcb.ioRefNum = goferresfile;
  98.        fcb.ioFCBIndx = 0;
  99.        PBGetFCBInfo(&fcb,FALSE);
  100.        gofervol = fcb.ioFCBVRefNum;
  101.        goferdirID = fcb.ioFCBParID;
  102.     }
  103.   else
  104.      (void) getwdinfo(goferWDRefNum, &gofervol, &goferdirID);
  105.  
  106.   savedir(gofervol,goferdirID,TRUE);
  107.  
  108.   (void) SysEnvirons(1, &environ);                 /* How old is this system?             */
  109.  
  110.   if (environ.machineType < 0)                     /* Negative if really old             */
  111.     {
  112.       WNEAvailable = FALSE;
  113.       CCAvailable = FALSE;
  114.       CIAvailable = FALSE;
  115.       HasAppleEvents = FALSE;
  116.       systemVersion = 0x0000;
  117.     }
  118.   else
  119.     {
  120.       WNEAvailable = TrapAvailable(WNETrapNumber, ToolTrap);
  121.       CCAvailable =  TrapAvailable(CCTrapNumber,  ToolTrap);
  122.       CIAvailable =  TrapAvailable(CITrapNumber,  ToolTrap);
  123.       systemVersion = environ.systemVersion;
  124.  
  125.       HasAppleEvents = systemVersion >= 0x0700;
  126.       if(HasAppleEvents)
  127.         InstallAEHandlers();
  128.     }
  129.  
  130.  if (WNEAvailable)
  131.       cursorRgn = NewRgn();
  132. }
  133.  
  134.  
  135.  
  136. /*****************************************************************************
  137.  
  138.     General event-handling code.
  139.  
  140. ******************************************************************************/
  141.  
  142.  
  143. /*
  144.   Disk Insertion event.
  145.  
  146.   Format the disk if an unformatted disk is inserted.
  147. */
  148.  
  149.  
  150. void DoDiskEvent()
  151. {
  152.   if (HiWord(myEvent.message) != noErr)
  153.     {
  154.        myEvent.where.h = ((qd.screenBits.bounds.right - qd.screenBits.bounds.left) / 2) - (304 / 2);
  155.        myEvent.where.v = ((qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) / 3) - (104 / 2);
  156.  
  157.        InitCursor();
  158.        (void) DIBadMount(myEvent.where, myEvent.message);
  159.      }
  160. }
  161.  
  162.  
  163.  
  164. /*
  165.   Handle menus -- whether from mouse downs or keys.
  166. */
  167.  
  168. void DoMenu(result,modifiers)
  169. long result;
  170. short modifiers;
  171. {
  172.   short menu = HiWord(result);
  173.   short item = LoWord(result);
  174.  
  175.   if (menu != 0 && item != 0)
  176.     {
  177.       Handle_Gofer_Menu(menu, item, modifiers);
  178.       drawcursor(myEvent, FALSE);
  179.       AdjustMenus(FALSE);
  180.     }
  181. }
  182.  
  183.  
  184.  
  185. /*
  186.     Window Zooming -- Macintosh System 3.2 or Later.
  187. */
  188.  
  189.  
  190. void DoZoom(whichWindow, code)
  191. WindowPtr whichWindow;
  192. short code;
  193. {
  194.   if (whichWindow != NIL)
  195.     {
  196.       if (TrackBox(whichWindow, myEvent.where, code) == TRUE)   
  197.         {
  198.           GrafPtr saveport;
  199.  
  200.           GetPort(&saveport);
  201.           SetPort(whichWindow);
  202.           EraseRect(&whichWindow->portRect);
  203.           ZoomWindow(whichWindow, code, TRUE);
  204.       SetPort(saveport);
  205.  
  206.           ResizeTheWindow(whichWindow);
  207.         }
  208.     }
  209. }
  210.  
  211.  
  212.  
  213. /*
  214.   Window resizing.
  215. */
  216.  
  217.  
  218. void DoGrow(whichWindow)
  219. WindowPtr  whichWindow;
  220. {
  221.   Rect  OldRect;
  222.   Rect  GrowRect;
  223.  
  224.   long  growResult;
  225.   short newWidth, newHeight;
  226.  
  227.   if (whichWindow != NIL)
  228.     {
  229.       /* Remember previous rectangle */
  230.       OldRect = whichWindow->portRect;
  231.  
  232.       /* Set the grow rectangle -- minimum 100x64; "infinite" maximum */
  233.       SetRect(&GrowRect, 100, 64, 32767, 32767);
  234.  
  235.       /* Get user input */
  236.       growResult = GrowWindow(whichWindow, myEvent.where, &GrowRect);
  237.       newWidth = LoWord(growResult);
  238.       newHeight = HiWord(growResult);
  239.  
  240.       /* If the new size is different from the previous one, resize the window appropriately */ 
  241.       if ( (newWidth != 0 && newHeight != 0)
  242.            && (newWidth != (OldRect.right - OldRect.left) || newHeight != (OldRect.bottom - OldRect.top)) )
  243.         {
  244.            GrafPtr saveport;
  245.  
  246.            GetPort(&saveport);
  247.            SetPort(whichWindow);
  248.            EraseRect(&whichWindow->portRect);
  249.            InvalRect(&whichWindow->portRect);
  250.        SetPort(saveport);
  251.  
  252.            SizeWindow(whichWindow, newWidth, newHeight, TRUE);
  253.            ResizeTheWindow(whichWindow);
  254.     }
  255.    }
  256. }
  257.  
  258.  
  259.  
  260. /*
  261.   Move a window.
  262. */
  263.  
  264. DoDrag(whichWindow) 
  265. WindowPtr  whichWindow;
  266. {
  267.   Rect  screenRect = qd.screenBits.bounds;
  268.   
  269.   SelectWindow(whichWindow);
  270.  
  271.   DragWindow(whichWindow, myEvent.where, &screenRect);
  272.  
  273.   MoveTheWindow(whichWindow);
  274. }
  275.  
  276.  
  277.  
  278. /*
  279.   Handle a press in a goaway box.
  280. */
  281.  
  282. DoGoAway(whichWindow)
  283. WindowPtr whichWindow;
  284. {
  285.   int windex;
  286.  
  287.   /* 
  288.       NB: This will not work for user-defined windows -- something
  289.       more sophisticated is needed.
  290.   */
  291.   if (TrackGoAway(whichWindow,myEvent.where))
  292.   
  293.     /* Normal Gofer window */
  294.     if((windex = findMyWindow(whichWindow))!=ILLEGAL_WINDOW)
  295.       {
  296.         if(myEvent.modifiers&optionKey)
  297.       IconiseWindow(windex);
  298.  
  299.         else if (closethewindow(windex,"closing"))
  300.           /* SKIP */;
  301.       }
  302.  
  303.     /* Desk accessory */
  304.     else if (((WindowPeek)whichWindow)->windowKind < 0)
  305.       {
  306.         CloseDeskAcc(((WindowPeek)whichWindow)->windowKind);
  307.         thefrontwindow = ILLEGAL_WINDOW;
  308.       }
  309.  
  310.     /* User-defined window */
  311.     else
  312.       {
  313.         HideWindow(whichWindow);
  314.         thefrontwindow = ILLEGAL_WINDOW;
  315.       }
  316. }
  317.  
  318.  
  319.  
  320. /*
  321.   Handle a mouse click in the body of a window.
  322.  
  323.   Select the window if it's not the front window.
  324.   Handle the mouse click after selecting the window
  325.   only if the window is iconic (so select and drag is
  326.   one operation rather than two for iconic windows).
  327. */
  328.  
  329. DoInContent(whichWindow)
  330. WindowPtr whichWindow;
  331. {
  332.   int windex = findMyWindow(whichWindow);
  333.   if(!iconic(windex) && whichWindow != FrontWindow())
  334.     SelectWindow(whichWindow);
  335.   else
  336.     {
  337.        SetPort(whichWindow);
  338.        DoTheWindow(whichWindow,&myEvent);
  339.     }
  340. }
  341.  
  342.  
  343.  
  344. /*
  345.   Handle window update events.
  346. */
  347.  
  348. void DoUpdate()
  349. {
  350.   WindowPtr whichWindow = (WindowPtr)myEvent.message;
  351.  
  352.   UpdateTheWindow(whichWindow);
  353. }
  354.  
  355.  
  356.  
  357. /*
  358.   Handle window activation/deactivation.
  359. */
  360.  
  361.  
  362. void DoActivate()
  363. {
  364.   /* Copy scrap whenever we become active */
  365.   if (thefrontwindow == ILLEGAL_WINDOW)
  366.     {
  367.       TEFromScrap();
  368.       loadscrap();
  369.     }
  370.  
  371.   ActivateTheWindow((WindowPtr)myEvent.message,
  372.             (myEvent.modifiers & activeFlag) != 0);
  373.   drawcursor(myEvent,TRUE);
  374. }
  375.  
  376.  
  377.  
  378. /*
  379.   Handle an OS event, such as MultiFinder suspend/resume.
  380. */
  381.  
  382. void DoOSEvent()
  383. {
  384.   if((myEvent.message & osEvtMessageMask) == SuspResEvt)
  385.     {
  386.      inForeground = (myEvent.message & resumeFlag) != 0;
  387.  
  388.       if (inForeground)
  389.         {
  390.       /* Resume Gofer */
  391.       WindowPtr frontwp;
  392.  
  393.       /* We only copy the System scrap to the TextEdit scrap if we're requested to */
  394.       if (myEvent.message & convertClipboardFlag)
  395.         {
  396.           TEFromScrap();
  397.           loadscrap();
  398.         }
  399.  
  400.       /* If the scrap has been hidden, then show it */
  401.       if ( scrapVisible && !((WindowPeek)WINDOW(scrap))->visible )
  402.         ShowWindow(WINDOW(scrap));
  403.  
  404.       /* Activate the frontmost window if there is one and it belongs to us */
  405.       frontwp = FrontWindow();
  406.       if (frontwp != NIL && ((WindowPeek)frontwp)->windowKind > 0)
  407.         ActivateTheWindow(FrontWindow(),TRUE);
  408.     }
  409.       else
  410.         {
  411.        /* Suspend Gofer */
  412.       if(thefrontwindow != ILLEGAL_WINDOW)
  413.         ActivateTheWindow(WINDOW(thefrontwindow),FALSE);
  414.  
  415.       if(scrapVisible)
  416.         HideWindow(WINDOW(scrap));
  417.      }
  418.       AdjustMenus(FALSE);
  419.     }
  420. }
  421.  
  422.  
  423. /*
  424.   Handle a high-level Apple Event, such as open application, 
  425.   print document etc.
  426.  
  427.   System-7 specific.
  428. */
  429.  
  430. void DoHighLevelEvent()
  431. {
  432.   OSErr resultCode;
  433.  
  434.   resultCode = AEProcessAppleEvent(&myEvent);
  435.   if (resultCode != noErr)
  436.     {
  437.       char resultStr[10];
  438.       sprintf(resultStr,"%u",resultCode);
  439.       paramtext("",resultStr,"","");
  440.       StopAlert(Res_AppleEvent_Failed_Alert,NIL);
  441.     }
  442.   else
  443.     AdjustMenus(FALSE);
  444. }
  445.  
  446.  
  447.  
  448. /* K and M define memory sizes for convenience when setting heap etc. */
  449.  
  450. #define    K    1024
  451. #define    M    K*K
  452.  
  453. #define MASTER_BLOCKS    5            /* How many extra blocks of handles to allocate.  This is a guess    */
  454.  
  455. InitMemory()
  456. {
  457.   long maxblock;                 /* Largest block during startup            */
  458.   unsigned heapsize;                      /* Heap size as determined during initialisation    */
  459.   int i;
  460.  
  461.   /* Set the stack space according to the amount of heap available */  
  462.  
  463.   heapsize = GetApplLimit() - ApplicZone();
  464.  
  465.   if(ExtraStack == 0)
  466.     ExtraStack = heapsize >   2*M? heapsize/15:
  467.                heapsize >   1*M?        32*K:
  468.                heapsize > 800*K?        16*K:
  469.                heapsize > 600*K?         8*K:
  470.              heapsize > 400*K?         4*K:
  471.                                        0*K;
  472.  
  473.   if(ExtraStack > 0)
  474.     SetApplLimit(GetApplLimit()-ExtraStack);
  475.  
  476.   for(i=0;i<MASTER_BLOCKS;++i)  
  477.     MoreMasters();                            /* Allow more handles                */
  478.   MaxApplZone();                              /* Extend the heap up to its limit         */
  479.  
  480.   /* Before even trying to start up, check our memory size */
  481.   if((maxblock=MaxBlock()) < MIN_INIT_SIZE)
  482.     {
  483.       SysBeep(3);
  484.       exit(1);
  485.     }
  486. }
  487.  
  488.  
  489.  
  490. /*****************************************************************************
  491.  
  492.     The main Program.
  493.  
  494. ******************************************************************************/
  495.  
  496.  
  497. extern Boolean running_interpreter;        /* Is the interpreter running? */
  498. static Boolean drawncursor = FALSE;             /* Don't redraw the cursor if drawing the cursor has triggered an update! */
  499. static Point lastMousePosn;            /* Where the mouse was last time */
  500.  
  501.  
  502. main()
  503. {
  504.   /* NB: DON'T DECLARE ANY shorts/floats/Booleans here -- Gofer will choke on them!        */
  505.  
  506.   long maxblock;                 /* Largest block during startup            */
  507.   int err;                     /* Error code from longjmp                */
  508.   
  509.   goferresfile = CurResFile();             /* Record the application resource file        */
  510.  
  511.   InitResData();                  /* Set up global constants             */
  512.  
  513.   InitMemory();                      /* Initialise Memory Parameters            */
  514.  
  515.  
  516.   /* Initialise the Macintosh Managers */
  517.  
  518.   InitGraf((Ptr) &qd.thePort);                /* Quickdraw                     */
  519.   InitFonts();                                /* Font Manager                     */
  520.   InitWindows();                              /* Window Manager                 */
  521.   InitMenus();                                /* Menu Manager                     */
  522.   TEInit();                                   /* Text Edit                     */
  523.   InitDialogs(NIL);                           /* Dialog Manager                 */
  524.   InitCursorCtl(NIL);                  /* Spinning Cursors                 */
  525.  
  526.  
  527.   ObtainEnvironment();                  /* Find the current setup             */
  528.   
  529.   FlushEvents (everyEvent,0 );                /* Clear all outstanding events             */
  530.   InitCursor();                               /* Set the arrow cursor                 */
  531.  
  532.   Init_Gofer_Menus();                         /* Initialise the menu bar             */
  533.  
  534.  
  535.   /*
  536.      Check for ridiculously low memory.
  537.      NB: Don't use FatalError here -- that jumps to catch_error,
  538.      which is undefined at this point!
  539.   */
  540.   
  541.   if((maxblock = MaxBlock()) < MinMemSize)
  542.     {
  543.       /*
  544.          Don't declare error as a char array: it consumes stack permanently
  545.      even if there's enough memory, and if not quadword aligned, can cause 
  546.      a crash during evaluation (in gcCStack)!
  547.       */
  548.  
  549.       char *error = malloc(50);
  550.  
  551.       if(error == NULL)
  552.         Error("Fatal ","Not enough memory to run MacGofer");
  553.  
  554.       else
  555.         {
  556.           sprintf(error,"MacGofer needs at least %uK free heap to run",MinMemSize/1024);
  557.           Error("Fatal ",error);
  558.     }
  559.  
  560.       exit(1);
  561.     }
  562.  
  563.  
  564.   /*
  565.       This is the re-entry point for errors during initialisation.  
  566.          catch_error must be initialised before *any* Gofer memory allocation.
  567.   */
  568.  
  569.   if((err=setjmp(catch_error)) ==0)                 /* Return here on failure during init         */
  570.     Init_Gofer();                           /* Gofer initialisation                 */
  571.  
  572.   /* There's some duplication here */
  573.   else if(!InterpreterInitialised)
  574.     {
  575.       RestorePrefs(TRUE);              /* Restore all preferences, including toggles     */
  576.  
  577.       InitOptionMenu();                  /* Initialse the options menu from these prefs    */
  578.  
  579.       if(GoferInitialised)
  580.         {
  581.           writeNewLine();              /* In case we were in the middle of a line     */ 
  582.           printPrompt();
  583.     }
  584.  
  585.       /* If we couldn't even install the Heap, let  the user know! */
  586.       if(!MemoryInstalledOK && !quit)
  587.      StopAlert(Res_MemoryNotInitialised_Alert,NIL);
  588.  
  589.       else
  590.         ResetInterpreter();              /* Reset the interpreter                 */
  591.  
  592.       InterpreterInitialised = MemoryInstalledOK;
  593.      }
  594.   else
  595.     {
  596.       /* 
  597.               This is the re-entry point for errors during evaluation etc.  
  598.       */
  599.  
  600. //  if(MemoryInstalledOK && (err=setjmp(catch_error)) !=0)   /* Return here on failure             */
  601. //    {
  602.       if(HandlingEvents)
  603.         useprojectresfile(FALSE,TRUE);          /* Forget any loaded resources             */
  604.  
  605.       windowtofront(worksheet);              /* Bring the worksheet back to the front     */
  606.  
  607.       writeNewLine();                  /* In case we were in the middle of a line     */ 
  608.  
  609.       /* This error is special: we can't call printf if we don't have any stack!! */
  610.  
  611.       if(err == 25)
  612.     mprintf("Error: the Macintosh stack collided with the heap\n");
  613.  
  614.       printPrompt();                  /* Output a prompt                */
  615.  
  616.       HideMenus(FALSE);                  /* Restore the menus                 */
  617.       HiliteMenu(0);                  /* Clear the menu bar in case "Loading"         */
  618.  
  619.       HideAllWindows(FALSE);              /* Restore our windows                 */
  620.  
  621.       ResetInterpreter();              /* Reset the interpreter                */
  622.  
  623.     }
  624.  
  625.   running_interpreter = FALSE;
  626.  
  627.   ResetCursor();                       /* Reset the cursor from a watch cursor        */
  628.  
  629.   if(TEHANDLE(worksheet) != NIL)
  630.     TEActivate(TEHANDLE(worksheet));         /* In case the worksheet insertion point got lost */
  631.  
  632.   resetinput();                     /* Reset the terminal IO                */
  633.  
  634.   AdjustMenus(TRUE);                 /* Reset the menus as if activating        */
  635.  
  636.   SetPt(&lastMousePosn,0,0);             /* Clear the last mouse position            */
  637.   
  638.   FlushKeyEvents();                 /* Handle any pent-up keyboard events         */
  639.  
  640.   while (!quit)                     /* Repeat the event loop until quit is TRUE     */
  641.     eventloop(everyEvent);
  642.   
  643.   SaveHiddenPrefs();                 /* Finally, save the hidden preferences        */
  644.  
  645. }
  646.  
  647.  
  648.  
  649. /*
  650.     One Cycle of the event loop.
  651. */
  652.  
  653.  
  654.  
  655. eventloop(evtmask)
  656. int evtmask;
  657. {  
  658.   getnextevent(evtmask);
  659.   
  660.   if (inForeground && thefrontwindow != ILLEGAL_WINDOW && isEditWindow(thefrontwindow))
  661.     TEIdle(TEHANDLE(thefrontwindow));              /* Blink the cursor                 */
  662.  
  663.   /*
  664.        Draw a cursor appropriate to the mouse location.
  665.        WaitNextEvent will notify us if we need to change the cursor.
  666.        Don't draw if the event is an update caused by the last
  667.        cursor draw or if the mouse hasn't moved between events.
  668.   */
  669.   
  670.   drawncursor &= myEvent.what == updateEvt;
  671.  
  672.   if (!drawncursor)
  673.     {
  674.       if(!EqualPt(myEvent.where,lastMousePosn))
  675.         {
  676.           drawcursor(myEvent, TRUE);
  677.           SetPt(&lastMousePosn,myEvent.where.h,myEvent.where.v);
  678.         }
  679.       drawncursor = TRUE;
  680.     }
  681.         
  682.   switch (myEvent.what)
  683.     {
  684.         short code;
  685.         WindowPtr  whichWindow;
  686.  
  687.            case mouseDown :
  688.               code = FindWindow(myEvent.where, &whichWindow);
  689.  
  690.               switch (code)
  691.                 {
  692.                   case inMenuBar :
  693.                     {
  694.               long result;
  695.               SetModifiedMenus(myEvent.modifiers);
  696.               result = MenuSelect(myEvent.where);
  697.               DoMenu(result,myEvent.modifiers);
  698.             }
  699.                     break;
  700.  
  701.                   case inDrag :
  702.                     DoDrag(whichWindow);
  703.                     break;
  704.  
  705.                   case inGrow :
  706.                     DoGrow(whichWindow);
  707.                     break;
  708.  
  709.                   case inZoomIn :
  710.                   case inZoomOut :
  711.                     DoZoom(whichWindow,code);
  712.                     break;
  713.  
  714.                   case inGoAway :
  715.                     DoGoAway(whichWindow);
  716.             AdjustMenus(FALSE);
  717.                     break;
  718.  
  719.                   case inContent :
  720.                     DoInContent(whichWindow);
  721.             AdjustMenus(FALSE);
  722.                     break;
  723.  
  724.                   case inSysWindow :
  725.                     SystemClick(&myEvent, whichWindow);
  726.             AdjustMenus(FALSE);
  727.                     break;
  728.  
  729.                   default:
  730.                     break;
  731.                 }
  732.               break;
  733.  
  734.             case keyDown:                     /* Key inputs */
  735.             case autoKey:                     /* and auto repeats */
  736.               DoKeyEvent(&myEvent,thefrontwindow,TRUE);
  737.               break;
  738.  
  739.             case updateEvt :                  /* Update event for a window */
  740.               DoUpdate();
  741.               break;
  742.  
  743.             case diskEvt :                    /* Disk inserted event */
  744.               DoDiskEvent();
  745.               break;
  746.  
  747.             case activateEvt :                /* Window activated event */
  748.             DoActivate();
  749.               break;
  750.           
  751.         case osEvt:
  752.           DoOSEvent();
  753.           break;
  754.  
  755.         case kHighLevelEvent:
  756.           DoHighLevelEvent();
  757.           break;
  758.  
  759.             default:
  760.               break;
  761.  
  762.     }
  763. }
  764.  
  765.  
  766. /*
  767.    Abstracted GetNextEvent/WaitNextEvent
  768. */
  769.  
  770. getnextevent(eventmask)
  771. int eventmask;
  772. {
  773.   /* Use WaitNextEvent if this is available -- this version blinks the cursor */
  774.  
  775.   if(running_interpreter && !EventAvail(eventmask,&myEvent))
  776.     return;
  777.     
  778.   if (WNEAvailable)
  779.     WaitNextEvent(eventmask, &myEvent, GetCaretTime(), cursorRgn);
  780.   else
  781.     {
  782.       /* Handle Desk accessories, if necessary. */
  783.       SystemTask();
  784.       GetNextEvent(eventmask, &myEvent);
  785.     }
  786. }
  787.  
  788.  
  789. /*
  790.      Terminate Gofer unless cancelled.
  791. */
  792.  
  793. Boolean Terminate_Gofer()
  794. {
  795.   return(closeallwindows());
  796. }
  797.  
  798.  
  799.  
  800. /*
  801.   Program Initialisation.
  802.  
  803.   Get the files to open or print, and open the standard
  804.   application windows (worksheet, scrap etc.) if running under 
  805.   Sys 6 or earlier.
  806.  
  807.   Just initialise the cursor resources under System 7.
  808. */
  809.  
  810. void InitApp()
  811. {
  812.   if(GoferInitialised)
  813.     return;
  814.  
  815.   Init_Gofer_Windows();
  816.  
  817.   /* Find the Location of the Prelude file */      
  818.   findPrelude();
  819.   InitPItems();
  820.   clearProject();
  821.  
  822.   /* Restore numeric and string preferences */      
  823.   RestorePrefs(FALSE);
  824.   
  825.   GoferInitialised = TRUE;
  826.  
  827.   /* 
  828.     Initialise the Gofer interpreter.
  829.   */
  830.   init_gofer();
  831.   
  832.   /* Restore all preferences, including toggles */
  833.   RestorePrefs(TRUE);
  834.   InitOptionMenu();
  835.  
  836.   InterpreterInitialised = TRUE;
  837. }
  838.  
  839. void OpenDoc(spec, filetype)
  840. FSSpec spec;
  841. OSType filetype;
  842. {
  843.   if (filetype == texttype)
  844.     doopenfile(p2cstr(spec.name),spec.vRefNum,spec.parID);
  845.  
  846.   else if (filetype == projtype)
  847.     doreadproject(p2cstr(spec.name),spec.vRefNum,spec.parID);
  848.  
  849.   else if (filetype == preftype)
  850.     dorestoreprefs(p2cstr(spec.name),spec.vRefNum,spec.parID,TRUE);
  851. }
  852.  
  853. void PrintDoc(spec)
  854. FSSpec spec;
  855. {
  856.   /* Print the given file */
  857.   int windex = doopenforprint(p2cstr(spec.name),spec.vRefNum,spec.parID);
  858.  
  859.   if(windex != ILLEGAL_WINDOW)
  860.     {
  861.       Print_Window(windex);
  862.       CloseAWindow(windex);
  863.     }
  864.   else
  865.     SysBeep(2);
  866. }
  867.  
  868. OSErr QuitApp(saveopt)
  869. DescType saveopt;
  870. {
  871.   savemethod = saveopt;
  872.   quit = Terminate_Gofer();           /* Quit */
  873.   if (quit)
  874.     return noErr;
  875.   else
  876.     {
  877.        savemethod = kAEAskUser;
  878.        return userCanceledErr;
  879.     }
  880. }
  881.  
  882. Init_Gofer()
  883. {
  884.   ibeamcurs = GetCursor(iBeamCursor);
  885.   watchcurs = GetCursor(watchCursor);
  886.   gccurs =    GetCursor(gcCursor);
  887.   if(CCAvailable)
  888.     gccursc =   GetCCursor(gcCursor);
  889.  
  890.   if(!HasAppleEvents)
  891.     {
  892.       short count, msg;
  893.       AppFile Params;
  894.  
  895.       windowtofront(worksheet);
  896.       
  897.       CountAppFiles(&msg,&count);
  898.       if(msg==appOpen)
  899.         InitApp();
  900.  
  901.       /* Handle initial open document/print requests */
  902.       if(count > 0)
  903.         {
  904.       short i;
  905.       FSSpec docSpec;
  906.  
  907.       for(i=1; i <= count; ++i)
  908.         {
  909.           GetAppFiles(i,&Params);
  910.  
  911.           if (getwdinfo(Params.vRefNum, &docSpec.vRefNum, &docSpec.parID) == noErr)
  912.             pstrcopy(Params.fName, docSpec.name);
  913.           else
  914.             continue;
  915.         
  916.               /* Resolve an alias, perhaps */
  917.               if(systemVersion >= 0x0700)
  918.                {
  919.                  Boolean wasFolder, wasAliased;
  920.                  ResolveAliasFile(&docSpec,TRUE,&wasFolder,&wasAliased);
  921.                }
  922.  
  923.           if(msg==appPrint)
  924.             PrintDoc(docSpec);
  925.           else
  926.             OpenDoc(docSpec, Params.fType);
  927.             }
  928.  
  929.       if(msg == appPrint)
  930.         exit(0);
  931.     }
  932.     }
  933. }
  934.  
  935.  
  936. /*
  937.   Draw a cursor appropriate to the current location.
  938. */
  939.  
  940. void LocalToGlobalRect(Rect *theRect)
  941. /* Converts a rectangle from local coordinates to global coordinates */
  942. {
  943.   Point topLeft, botRight;
  944.  
  945.   SetPt(&topLeft, theRect->left, theRect->top);
  946.   LocalToGlobal(&topLeft);
  947.   SetPt(&botRight, theRect->right, theRect->bottom);
  948.   LocalToGlobal(&botRight);
  949.  
  950.   SetRect(theRect, topLeft.h, topLeft.v, botRight.h, botRight.v);
  951. }
  952.  
  953. drawcursor(event, adjustRegion)
  954. EventRecord event;
  955. Boolean adjustRegion;
  956. {
  957.   Rect worldRect;
  958.  
  959. /* If we're in the background, or a DA is active, we don't need to fiddle with the cursor */
  960.   if (!inForeground || (FrontWindow() != NIL && ((WindowPeek)FrontWindow())->windowKind < 0))
  961.     return;
  962.  
  963. /* Find the rectangle enclosing our virtual "world" if we need to calculate the cursor region */
  964.   if (adjustRegion)
  965.     {
  966.       if (systemVersion >= 0x0410)
  967.         worldRect = (**GetGrayRgn()).rgnBBox;
  968.       else
  969.         worldRect = qd.screenBits.bounds;
  970.     }
  971.  
  972. /* If we have an editable window, then we need to put up either an I-beam or an arrow cursor */
  973.   if (thefrontwindow != ILLEGAL_WINDOW && isEditWindow(thefrontwindow))
  974.     {
  975.       Rect globalTextRect;
  976.       GrafPtr saveport;
  977.  
  978.       GetPort(&saveport);
  979.       SetPort(WINDOW(thefrontwindow));
  980.  
  981.       globalTextRect = (*TEHANDLE(thefrontwindow))->viewRect;
  982.       LocalToGlobalRect(&globalTextRect);
  983.  
  984.       if (PtInRect(event.where, &globalTextRect))
  985.         {
  986.           SetCursor(*ibeamcurs);
  987.           if (adjustRegion)
  988.         RectRgn(cursorRgn, &globalTextRect);
  989.         }
  990.       else
  991.         {
  992.           SetCursor(&(qd.arrow));
  993.         }
  994.  
  995.       SetPort(saveport);
  996.     }
  997. /* If we don't have an editable window, then we just need an arrow */
  998.   else
  999.     {
  1000.       SetCursor(&(qd.arrow));
  1001.       if (adjustRegion)
  1002.         RectRgn(cursorRgn, &worldRect);
  1003.     }
  1004. }
  1005.  
  1006.  
  1007.  
  1008. safeexit(n)
  1009. {
  1010.   mprintf("\n{{Gofer interpreter exited, code %d}}\n",n);
  1011.   longjmp(catch_error,n);
  1012. }
  1013.